package com.lpf;

import com.google.common.base.Charsets;
import com.google.common.io.Resources;
import graphql.GraphQL;
import graphql.schema.GraphQLSchema;
import graphql.schema.idl.RuntimeWiring;
import graphql.schema.idl.SchemaGenerator;
import graphql.schema.idl.SchemaParser;
import graphql.schema.idl.TypeDefinitionRegistry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.net.URL;

import static graphql.schema.idl.TypeRuntimeWiring.newTypeWiring;

@SuppressWarnings("UnstableApiUsage")
@Component
public class GraphQLProvider {

    // 默认处理"/graphql"这个 path 上的全部请求；
    private GraphQL graphQL;

    @Bean
    public GraphQL graphQL() {
        return graphQL;
    }

    @PostConstruct
    public void init() throws IOException {
        // 读取 GraphQL Schema 文件并创建 GraphQL 实例，该 GraphQL 实例会通过上面的 graphQL() 方
        // 法暴露给 Spring，默认情况下，请求到"/graphql"这个 path 上的请求都会由该 GraphQ L实例处理
        URL url = Resources.getResource("book.graphqls");
        String sdl = Resources.toString(url, Charsets.UTF_8);
        GraphQLSchema graphQLSchema = buildSchema(sdl);
        this.graphQL = GraphQL.newGraphQL(graphQLSchema).build();
    }

    private GraphQLSchema buildSchema(String sdl) {
        // GraphQL Schema 文件被解析之后，就是这里的 TypeDefinitionRegistry 对象
        TypeDefinitionRegistry typeRegistry = new SchemaParser().parse(sdl);
        // 注册 DataFetcher。DataFetcher 的核心功能是：获取查询字段的相应数据
        RuntimeWiring runtimeWiring = buildWiring();
        SchemaGenerator schemaGenerator = new SchemaGenerator();
        // 将 GraphQL Schema 中定义的与 DataFetcher 关联起来
        return schemaGenerator.makeExecutableSchema(typeRegistry, runtimeWiring);
    }

    @Autowired
    private GraphQLDataFetchers graphQLDataFetchers;

    private RuntimeWiring buildWiring() {
        return RuntimeWiring
                .newRuntimeWiring()
                // 将 Query.getById 与 getBookByIdDataFetcher() 方法返回的 DataFetcher 实现关联
                .type(newTypeWiring("Query")
                        .dataFetcher("getById", graphQLDataFetchers.getBookByIdDataFetcher())
                        .dataFetcher("list", graphQLDataFetchers.listDataFetcher())
                        .dataFetcher("getBookById", graphQLDataFetchers.getBookByIdDataFetcher())
                )
                // 将Book.author字段与getAuthorDataFetcher()方法返回的DataFetcher实现关联
                .type(newTypeWiring("Book").dataFetcher("author", graphQLDataFetchers.getAuthorDataFetcher()))
                .build();
    }

}